package com.zxy.supplier_system.server.controller

import com.zxy.supplier_system.server.entity.Authority
import com.zxy.supplier_system.server.service.EmployeeService
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.server.ResponseStatusException
import java.lang.annotation.Inherited

@Component
@Aspect
class AuthorityAspect(
    private val employeeService: EmployeeService
) {


    @Before("@annotation(HasAuthority) || @annotation(HasAnyAuthority) || @annotation(HasAllAuthority)")
    fun checkAuthority(joinPoint: JoinPoint) {
        val signature = joinPoint.signature
        if (signature is MethodSignature) {
            signature.method.getAnnotation(HasAuthority::class.java)?.let {
                if (!employeeService.getRequiredCurrentEmployee().authorities.contains(it.value)) {
                    throw ResponseStatusException(HttpStatus.FORBIDDEN)
                }
            }
            signature.method.getAnnotation(HasAnyAuthority::class.java)?.let { annotation ->
                if (!employeeService.getRequiredCurrentEmployee().authorities.any {
                        annotation.value.contains(it)
                    }) {
                    throw ResponseStatusException(HttpStatus.FORBIDDEN)
                }
            }

            signature.method.getAnnotation(HasAllAuthority::class.java)?.let { annotation ->
                if (!employeeService.getRequiredCurrentEmployee().authorities.containsAll(annotation.value.toList())) {
                    throw ResponseStatusException(HttpStatus.FORBIDDEN)
                }
            }
        }
    }

}


@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention
@Inherited
@MustBeDocumented
annotation class HasAuthority(
    val value: Authority
)

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention
@Inherited
@MustBeDocumented
annotation class HasAnyAuthority(
    vararg val value: Authority
)

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention
@Inherited
@MustBeDocumented
annotation class HasAllAuthority(
    vararg val value: Authority
)